package com.sta.oldman.coder;

import com.fazecast.jSerialComm.SerialPort;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;


public class SerialPortListener {

    private static final List<byte[]> receivedFrames = new CopyOnWriteArrayList<>();//将获取到的帧缓存起来

    public static String getAndClearFrames() {
        List<byte[]> copy = new ArrayList<>(receivedFrames);
        StringBuilder sb = new StringBuilder();
        for (byte[] frame : copy) {
            sb.append(bytesToHex(frame)).append("\n");
        }
        receivedFrames.clear();
        return sb.toString();
    }


    private final ByteArrayOutputStream frameBuffer = new ByteArrayOutputStream();

    public void init() {
        SerialPort comPort = SerialPort.getCommPort("COM6");
        comPort.setBaudRate(115200);
        if (comPort.openPort()) {
            System.out.println("串口已打开");
        } else {
            System.out.println("打开串口失败");
            return;
        }

        new Thread(() -> {
            byte[] buffer = new byte[1024];
            while (comPort.isOpen()) {
                int bytesRead = comPort.readBytes(buffer, buffer.length);
                if (bytesRead > 0) {
                    frameBuffer.write(buffer, 0, bytesRead);
                    processFrameBuffer();
                }
            }
        }).start();
    }

    private void processFrameBuffer() {
        byte[] data = frameBuffer.toByteArray();
        int i = 0;
        while (i <= data.length - 9) { // 最小帧长为9字节
            if (data[i] == (byte) 0x53 && data[i + 1] == (byte) 0x59) {//只有遇到帧头标识才进行校验,否则跳过
                // 小端解析长度字段
                int dataLen = ((data[i + 4] & 0xFF) << 8) | (data[i + 5] & 0xFF);
                int fullFrameLen = 2 + 1 + 1 + 2 + dataLen + 1 + 2;

                if (i + fullFrameLen > data.length) break; // 不够一帧，等待更多数据

//                 校验帧尾
                if ((data[i + fullFrameLen - 2] == (byte) 0x54)) { // 容忍帧尾第二字节变动
                    byte[] frame = Arrays.copyOfRange(data, i, i + fullFrameLen);

                    // 校验码验证
                    if (verifyChecksum(frame)) {
                        receivedFrames.add(frame);
                    }

                    i += fullFrameLen;
                }
                else {
                    i++; // 帧尾不符，跳过该字节
                }
            } else {
                i++; // 非帧头
            }
        }

        // 剩余未处理的字节写回缓存区
        byte[] remain = Arrays.copyOfRange(data, i, data.length);
        frameBuffer.reset();
        frameBuffer.write(remain, 0, remain.length);
    }
    private boolean verifyChecksum(byte[] frame) {
        int len = frame.length;
        int checksumIndex = len - 3;

        int sum = 0;
        for (int i = 0; i < checksumIndex; i++) {
            sum += (frame[i] & 0xFF);
        }

        int expected = sum & 0xFF;
        int actual = frame[checksumIndex] & 0xFF;

        return expected == actual;
    }


    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X ", b));
        }
        return sb.toString().trim();
    }

    public static void main(String[] args) {
        SerialPortListener serialPortListener = new SerialPortListener();
        serialPortListener.init();
        while (true) {
            System.out.println(getAndClearFrames());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}